#ifndef LECTEURPHRASEABSTRAIT_H
#define LECTEURPHRASEABSTRAIT_H

#include "Symbole.h"
#include "LecteurSymbole.h"
#include "TableSymboles.h"
#include "Arbre.h"

#include <stdlib.h>
#include <string>

////////////////////////////////////////////////////////////////////////////////
/*! \file LecteurPhraseAbstrait.h
\brief La spécification de la classe LecteurPhraseAbstrait
Décrit la liste des méthodes et attributs associés à la classe LecteurPhraseAbstrait
\author Pierre-Antoine Forestier & Vincent Plantier
\date 19.12.2012
 */

/*! \class LecteurPhraseAbstrait
\brief La classe abstraite représentant un lecteur basé sur l'architecture 'Arbre & noeuds' permettant
 à l'interpreteur d'effectuer une analyse afin d'interpreter le programme (classe LecteurPhraseAvecArbre)
 ou une fonction(classe LecteurFonction).
Les méthodes suivantes sont associées à un objet de type LecteurPhraseAvecArbre :
\li LecteurPhraseAvecArbre
\li analyse
\li genCode
\li programme
\li seqInst
\li inst
\li affectation
\li fonction
\li expression
\li terme
\li facreur
\li opAdd
\li opMult
\li opBool
\li opRel
\li opUnaire
\li expBool
\li expEt
\li relation
\li instSi
\li instLire
\li instEcrire
\li instTq
\li instPour
\li instRepeter
\li testerSymCour
\li sauterSymCour
\li erreur
\li getTs
\li getArbre
\li ajFonction

 */




class LecteurPhraseAbstrait {
public:
    LecteurPhraseAbstrait();
    void analyse();

    inline TableSymboles getTs() {
        return ts;
    } // accesseur

    inline Noeud* getArbre() {
        return arbre;
    } // accesseur
    // ajouter une fonction à la table des fonctions

    void ajFonction(LecteurPhraseAbstrait* f) {
        tf.push_back(f);
    }
protected:
    /*! \var LecteurSymbole *ls
        \brief Contient le lecteur de symboles utilisé pour analyser le fichier.
     */
    LecteurSymbole *ls;
    /*! \var TableSymboles ts
        \brief Contient la table des symboles valués.
     */
    TableSymboles ts;
    /*! \var  Noeud* arbre
        \brief Contient l'arbre abstrait.
     */
    Noeud* arbre;
    /*! \var  vector <LecteurPhraseAbstrait *> tf
        \brief Contient les fonctions pouvant être appelés dans une instruction.
     */
    vector <LecteurPhraseAbstrait *> tf;
    // implémentation de la grammaire
    /*! \fn programme()
        \brief Méthode abstraite pour générer l'instance de l'attribut arbre.\n
            Règle BNF dans LecteurPhraseAvecArbre : <programme> ::= <seqFonc> debut <seqInst> fin FIN_FICHIER\n
            Règle BNF dans LecteurFonction : <programme> ::= fonction <variable> ([<variable>{,<variable>}]) <seqInst> [<instRetour>] finfonc
     */
    virtual Noeud* programme() = 0;

    /*! \fn seqInst()
        \brief Règle BNF : <seqInst> ::= <inst> ; { <inst> ; }
     */
    Noeud* seqInst();

    /*! \fn inst()
    \brief Règle BNF : <inst> ::= <affectation> | <instPour> | <instSi> | <instTq> | <instRepeter> | <insLire> | <instEcrire> | <fonction>; 
     */
    Noeud* inst();

    /*! \fn affectation()
    \brief Règle BNF : <affectation> ::= <variable> = <expression> | <variable>++ | <variable>--
     */
    Noeud* affectation();

    Noeud* affectation(Symbole &s);
    /*! \fn fonction(Symbole &s)
        \brief Règle BNF :  <fonction> ::= <variable> ([<expression>{,<expression>}])\n
          Au moment de l'appel, on a déjà lu le nom de la fonction contenu dans symbole et on est passé au symbole suivant
        \param s : symbole nom de la fonction
     */
    Noeud* fonction(Symbole &s);
    /*! \fn expression()
    \brief Règle BNF : <expression> ::= <terme> { <opAdd> <terme> }
     */
    Noeud* expression();

    /*! \fn facteur()
    \brief Règle BNF : <facteur> ::= <entier>  |  <variable> | <fonction> |  - <exBool>  |  ( <expBool> )
     */
    Noeud* facteur();

    /*! \fn opAdd()
    \brief Règle BNF : <opAdd>  ::= + | -
     */
    Symbole opAdd();

    /*! \fn opMult()
    \brief Règle BNF : <opMult>  ::= * | /
     */
    Symbole opMult();

    /*! \fn opBool()
    \brief Règle BNF : <opBool>  ::= et | ou
     */
    Symbole opBool();


    /*! \fn opRel()
    \brief Règle BNF : <opRel>  ::= == | != | >= | <= | > | <
     */
    Symbole opRel();

    /*! \fn opUnaire()
    \brief Règle BNF : <opUnaire>  ::= - | non
     */
    Symbole opUnaire();

    /*! \fn expBool()
    \brief Règle BNF : : <expBool>::=<expEt> {ou <expEt>}
     */
    Noeud* expBool();

    /*! \fn expEt()
    \brief Règle BNF <expEt>::=<relation> {et <relation>}
     */
    Noeud* expEt();

    /*! \fn relation()
    \brief Règle BNF : <relation>::=<expression> {<opRel> <expression>}
     */
    Noeud* relation();

    /*! \fn instSi()
    \brief Règle BNF : <instSi>::= si(<expBool>) <seqInst> { sinonsi(<expBool>)<seqInst>}[sinon<seqInst>] finsi
     */
    Noeud* instSi();

    /*! \fn instLire()
    \brief Règle BNF : <instLire> ::=lire(<variable>)
     */
    Noeud* instLire();

    /*! \fn instEcrire()
    \brief Règle BNF : <instEcrire>::= ecrire(<chaine> | <expression>)
     */
    Noeud* instEcrire();

    /*! \fn instTq()
    \brief Règle BNF :  <instTq>::=tantque (<expBool>) <seqInst> fintantque
     */
    Noeud* instTq();

    /*! \fn instPour()
    \brief Règle BNF :  <instPour> ::= pour (<affectation>;<expBool>;<affectation>) <seqInst> finpour
     */
    Noeud* instPour();

    /*! \fn instRepeter()
    \brief Règle BNF : repeter <seqInst> jusqua (<expBool>)
     */
    Noeud* instRepeter();

    /*! \fn terme()
    \brief Règle BNF : <terme> ::= <facteur> {<opmult> <facteur>}
     */
    Noeud* terme();

    /*! \fn testerSymCour(string ch)
    \brief Si le symbole courant != ch, on déclenche une erreur : on arrete le programme, sinon le programme continue
    \param ch : la chaine correspondant au symbole attendu
     */
    void testerSymCour(string ch);

    /*! \fn sauterSymCour(string ch)
    \brief Si le symbole courant == ch, on passe au symbole suivant, sinon on déclenche une erreur : on arrete le programme
    \param ch : la chaine correspondant au symbole attendu
     */
    void sauterSymCour(string ch);

    /*! \fn erreur(string mess)
    \brief On affiche le message d'erreur spécifique pour le symbole attendu mess et on arrete le programme
    \param mess : chaine correspondant au symbole attendu
     */
    void erreur(string mess);
};

#endif // LECTEURPHRASEABSTRAIT_H